<!--
 * @Description: 驾驶舱
 * @FilePath: \hk-computerRoom-Security\src\views\home\index.vue
 * @Date: 2024-02-19 16:09:03
 * @LastEditTime: 2024-02-27 10:22:38
-->

<template>
	<div class="home-container">
		<div class="three-area">
			<div class="three-box" ref="threeDemoRef"></div>
			<div ref="dialogRef" id="myDialog" style="display: none"></div>
			<LoadTransition :loading="state.loading" :percentage="state.progress"></LoadTransition>
		</div>

		<div class="home-main">
			<HomeHead v-if="isTagsViewCurrenFull" @refresh="state.isFullScreen = false"></HomeHead>
			<div class="echarts-area">
				<div class="echarts-info">
					<EchartLeakage class="echarts-box"></EchartLeakage>
					<AlarmHistory class="echarts-box" :type="2"></AlarmHistory>
					<div v-if="state.isFullScreen == false" class="fullScreen" @click.stop="state.isFullScreen = true">全屏</div>
				</div>
				<div class="data-info" :class="state.isFullScreen ? '' : 'pt20'">
					<div class="count-list">
						<div class="info-box">
							<img src="../../assets/images/home/icon1.svg" alt="" class="info-img" />
							<div class="info-text">
								<div class="info-name">网关总数/台</div>
								<div class="info-count">
									{{ state.deviceCount.gateway_total_num }}
								</div>
							</div>
						</div>
						<div class="info-box">
							<img src="../../assets/images/home/icon2.svg" alt="" class="info-img" />
							<div class="info-text">
								<div class="info-name">设备总数/台</div>
								<div class="info-count">
									{{ state.deviceCount.device_total_num }}
								</div>
							</div>
						</div>
						<div class="info-box">
							<img src="../../assets/images/home/icon2.svg" alt="" class="info-img" />
							<div class="info-text">
								<div class="info-name">设备在线数/台</div>
								<div class="info-count">
									{{ state.deviceCount.device_online_num }}
								</div>
							</div>
						</div>
						<div class="info-box">
							<img src="../../assets/images/home/icon3.svg" alt="" class="info-img" />
							<div class="info-text">
								<div class="info-name">漏水报警设备数/台</div>
								<div class="info-count">
									{{ state.deviceCount.device_leakage_alarm_num }}
								</div>
							</div>
						</div>
						<div class="info-box">
							<img src="../../assets/images/home/icon4.svg" alt="" class="info-img" />
							<div class="info-text">
								<div class="info-name">温度报警设备数/台</div>
								<div class="info-count">
									{{ state.deviceCount.device_temperature_alarm_num }}
								</div>
							</div>
						</div>
					</div>

					<div class="change-room">
						<div class="room-item" v-for="item in state.roomList" :key="item" @click.stop="state.selected = item">
							<img src="../../../src/assets/images/home/icon-open.svg" alt="" v-if="state.selected === item" />
							<img src="../../../src/assets/images/home/icon-close.svg" alt="" v-else />
							<div :class="state.selected === item ? 'room-title' : ''">{{ item }}</div>
						</div>
					</div>
				</div>
				<div class="echarts-info">
					<EchartTemperature class="echarts-box"></EchartTemperature>
					<AlarmHistory class="echarts-box" :type="1"></AlarmHistory>
				</div>
			</div>
		</div>
	</div>
</template>

<script setup lang="ts" name="home">
import { reactive, ref, defineAsyncComponent, watch, onMounted, onUnmounted } from 'vue';
import { useDataBoardApi } from '/@/api/dataBoard';
import { useTagsViewRoutes } from '/@/stores/tagsViewRoutes';
import { storeToRefs } from 'pinia';
import EchartTemperature from './component/echart-temperature.vue';
import AlarmHistory from './component/alarm-history.vue';
import EchartLeakage from './component/echart-leakage.vue';
// 引入模型加载过渡动画
import LoadTransition from './component/loading.vue';
// 引入three.js
import * as THREE from 'three';
import {
	scene,
	composer,
	outlinePass,
	getDomInfo,
	init,
	createControls,
	initLight,
	createCSS3DRenderer,
	getIntersectPoint,
	addOutlineEffect,
	watchDom,
	renderResize,
	renderLoop,
} from './component/threeD/init.js';
// 引入gltf模型加载库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
// 引入CSS3模型对象CSS3DObject
import { CSS3DObject } from 'three/addons/renderers/CSS3DRenderer.js';
const loader = new GLTFLoader();
const tagsViewRoutesStore = useTagsViewRoutes();
const { isTagsViewCurrenFull } = storeToRefs(tagsViewRoutesStore);
const HomeHead = defineAsyncComponent(() => import('/@/views/home/component/home-head.vue'));
const threeDemoRef = ref();
const dialogRef = ref();

let model: any = null;
const state: any = reactive({
	isFullScreen: true, // 是否全屏
	selected: '机房1',
	roomList: ['机房1', '机房2', '机房3'],
	deviceCount: {
		gateway_total_num: 0,
		device_total_num: 0,
		device_online_num: 0,
		device_leakage_alarm_num: 0,
		device_temperature_alarm_num: 0,
	},

	loading: true, // 是否开启加载动画
	progress: 0, // 模型加载进度
	randomObject: null, // 随机选中的正常设备
	selectedDevice: null, // 点击选中的设备
	intervalId: null, // 定时器
	// 报警设备
	alarmInfo: [
		{
			name: 'AU02',
			temperature: '35℃', // 温度
			tempState: '1', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '1', // 漏水报警状态 0正常 1报警
			status: 1,
		},
		{
			name: 'AU08',
			temperature: '38℃', // 温度
			tempState: '1', // 温度报警状态 0正常 1报警
			leakage: '60', // 漏水
			leakageState: '1', // 漏水报警状态 0正常 1报警
			status: 1,
		},
		{
			name: 'AU18',
			temperature: '40℃', // 温度
			tempState: '1', // 温度报警状态 0正常 1报警
			leakage: '72', // 漏水
			leakageState: '1', // 漏水报警状态 0正常 1报警
			status: 1,
		},
	],
	// 正常设备
	normalInfo: [
		{
			name: 'AU01',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU03',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU04',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU05',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU06',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU07',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU09',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU10',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU11',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU12',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU13',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU14',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU15',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU16',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU17',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU19',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU20',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU21',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
		{
			name: 'AU22',
			temperature: '35℃', // 温度
			tempState: '0', // 温度报警状态 0正常 1报警
			leakage: '58', // 漏水
			leakageState: '0', // 漏水报警状态 0正常 1报警
			status: 0,
		},
	],
	allDeviceObjList: [], // 所有设备obj
});

onMounted(async () => {
	queryDeviceCount();

	getDomInfo(threeDemoRef.value);
	init(threeDemoRef.value);
	importModel();
	createControls();
	initLight();
	createCSS3DRenderer(threeDemoRef.value);
	watchDom(threeDemoRef.value);
	renderResize(threeDemoRef.value);
	renderLoop();
});

onUnmounted(() => {
	// 停止定时器
	clearInterval(state.intervalId);

	// 从场景中移除模型
	scene.remove(model.value);

	// 释放模型资源
	model.traverse((child: any) => {
		if (child instanceof THREE.Mesh) {
			child.geometry.dispose();
			child.material.dispose();
		}
	});

	window.removeEventListener('click', onClick);
});

// 导入模型
const importModel = () => {
	loader.load(
		'model/room1.glb',
		(gltf: any) => {
			model = gltf.scene;
			model.rotation.set(0, -Math.PI / 12, 0);
			model.position.set(0, -5, 0);
			model.traverse(function (child: any) {
				if (child.isMesh) {
					// 1.去掉文字
					if (child.name == 'Text') child.visible = false;
					// 2.修复设备颜色偏暗的问题
					if (child.parent.name.includes('AU')) {
						child.frustumCulled = false;
						//模型阴影
						child.castShadow = true;
						//模型自发光
						child.material.emissive = child.material.color;
						child.material.emissive.setHSL(1, 0, 0.35);
						child.material.emissiveMap = child.material.map;
					}
				}
			});
			create3DDialog();
			scene.add(model);
		},
		(xhr: any) => {
			// 计算加载进度百分比
			state.progress = Math.floor((xhr.loaded / xhr.total) * 100);
			if (state.progress == 100) state.loading = false;
		},
		// 模型加载错误
		(error: any) => {
			console.log(error, 'error');
		}
	);
};

// 创建3D弹框
const create3DDialog = () => {
	createAlarmDialog();
	createNormalDialog();
};

// 创建常亮(报警信息框)
const createAlarmDialog = () => {
	state.allDeviceObjList = [];
	model.traverse((obj: any) => {
		if (obj.name.includes('AU')) {
			state.allDeviceObjList.push(obj);
			// 报警数据持续展示
			state.alarmInfo.forEach((item: any) => {
				if (item.name == obj.name) {
					insertDialogHtml(obj, item);
				}
			});
		}
	});
};

// 创建随机(正常信息框)
const createNormalDialog = () => {
	// 过滤出正常设备的obj
	const filteredEquipment = state.allDeviceObjList.filter((item: any) => !['AU02', 'AU08', 'AU18'].includes(item.name));
	let index = state.normalInfo.length - 1;
	state.intervalId = setInterval(() => {
		// 移除上一个dialog
		clearDialog();
		index = index == state.normalInfo.length - 1 ? 0 : ++index;
		const randomInfo = state.normalInfo[index];
		const randomObject = filteredEquipment.filter((item: any) => item.name == randomInfo.name);
		state.randomObject = randomObject[0];
		insertDialogHtml(state.randomObject, randomInfo);
	}, 3000);
};

// 插入弹框html
const insertDialogHtml = (obj: any, item: any) => {
	// 多个标签-需要克隆复制一份
	const div: any = dialogRef.value.cloneNode();
	div.innerHTML = `
  <div class="box-container">
    <div class=${item.status == 0 ? 'tip-green' : 'tip-red'} >
			<div class="title">设备名称 : ${item.name}</div>
			<div class="label-text">
				温度 :
				<span class="mr5" class=${item.tempState == '0' ? 'label-value-green' : 'label-value-red'}>
          ${item.temperature}
				</span>
				<span class=${item.tempState == '0' ? 'label-value-green' : 'label-value-red'}>
				 ${item.tempState == '0' ? '正常' : '报警'}
				</span>
			</div>
			<div class="label-text">
				漏水 :
				<span class="mr5" class=${item.leakageState == '0' ? 'label-value-green' : 'label-value-red'}>
          ${item.leakage}
        </span>
				<span class=${item.leakageState == '0' ? 'label-value-green' : 'label-value-red'}>
					${item.leakageState == '0' ? '正常' : '报警'}
				</span>
			</div>
		</div>
    <div class=${item.status == 0 ? 'line-green' : 'line-red'}></div>
  </div>
		  `;
	// HTML元素转化为threejs的CSS3对象
	const dialog = new CSS3DObject(div);
	//避免标签遮挡canvas鼠标事件
	div.style.pointerEvents = 'none';
	dialog.name = obj.name + 'dialog';
	dialog.scale.set(0.1, 0.1, 1);
	dialog.position.set(0, 6, 0);
	// 判断是否需要旋转
	const nameList = ['AU04', 'AU07', 'AU08', 'AU09', 'AU10', 'AU11', 'AU16', 'AU17', 'AU18', 'AU19', 'AU20'];
	if (nameList.includes(obj.name)) {
		dialog.rotation.set(0, -Math.PI / 2, 0);
	}
	obj.add(dialog);
};

// 清除前一个随机框
const clearDialog = () => {
	if (state.randomObject) {
		const currentRandomObject = model.getObjectByName(state.randomObject.name + 'dialog');
		currentRandomObject ? currentRandomObject.parent.remove(currentRandomObject) : '';
		state.randomObject = null;
	}
};

// 重置(清除呼吸灯和弹框,并继续随机显示正常设备的信息)
const resetRandomDialog = () => {
	if (outlinePass) {
		composer.removePass(outlinePass);
		clearDialog();
		createNormalDialog();
	}
};

const onClick = (event: any) => {
	event.preventDefault();
	const intersects = getIntersectPoint(event);
	if (intersects.length) {
		const selectedDevice = intersects[0].object.parent;
		if (selectedDevice.name && selectedDevice.name.includes('AU')) {
			// 1.停止当前随机信息展示
			state.intervalId ? clearInterval(state.intervalId) : '';
			// 2.清除前一个弹框
			clearDialog();
			// 3.报警设备只添加呼吸灯效果,正常设备添加呼吸灯+弹框
			state.selectedDevice = { ...selectedDevice };
			const alarmName = state.alarmInfo.map((item: any) => item.name);
			if (alarmName.includes(selectedDevice.name)) {
				addOutlineEffect([selectedDevice], 0x8b1616);
			} else {
				addOutlineEffect([selectedDevice], 0x21793b);
				model.traverse((obj: any) => {
					if (obj.name.includes('AU') && obj.name == selectedDevice.name) {
						state.normalInfo.forEach((item: any) => {
							if (item.name == selectedDevice.name) {
								state.randomObject = { ...selectedDevice };
								insertDialogHtml(obj, item);
							}
						});
					}
				});
			}
		} else {
			resetRandomDialog();
		}
	} else {
		resetRandomDialog();
	}
};

window.addEventListener('click', onClick, false);

// 获取设备相关数据
const queryDeviceCount = async () => {
	const { data } = await useDataBoardApi().queryDeviceCount({
		// energyTypeCode: '',
		// organizationId: '',
	});
	state.deviceCount = data;
};

watch(
	() => state.isFullScreen,
	(newVal: boolean) => {
		tagsViewRoutesStore.setCurrenFullscreen(newVal);
	},
	{
		immediate: true,
	}
);
</script>

<style scoped lang="scss">
@import './index.scss';
</style>
